/*******************************************************************************
 * * Copyright 2012 Impetus Infotech.
 *  *
 *  * Licensed under the Apache License, Version 2.0 (the "License");
 *  * you may not use this file except in compliance with the License.
 *  * You may obtain a copy of the License at
 *  *
 *  *      http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  * Unless required by applicable law or agreed to in writing, software
 *  * distributed under the License is distributed on an "AS IS" BASIS,
 *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  * See the License for the specific language governing permissions and
 *  * limitations under the License.
 ******************************************************************************/
package cn.ilikes.tools.nosql.jpa.metadatas.processor.processores;

import java.lang.reflect.Field;
import java.util.Arrays;

import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;

import org.slf4j.Logger;

import cn.ilikes.tools.logs.Loggerfactory;
import cn.ilikes.tools.nosql.jpa.JPASQLRunTimeException;
import cn.ilikes.tools.nosql.jpa.metadatas.EntityMetaData;
import cn.ilikes.tools.nosql.jpa.metadatas.elements.EntityFields;
import cn.ilikes.tools.nosql.jpa.metadatas.elements.JPAField;
import cn.ilikes.tools.nosql.jpa.metadatas.elements.Relation;
import cn.ilikes.tools.nosql.jpa.metadatas.processor.validators.EntityValidatorException;

/**
 * The Class OneToOneRelationMetadataProcessor.
 * 
 * @author Amresh Singh
 */
public class OneToOneRelationProcessor implements Processors {
	private static Logger logger = Loggerfactory.instance(OneToOneRelationProcessor.class);

	@Override
	public void validators(Class<?> clazz, EntityMetaData metadata) throws EntityValidatorException {

	}

	@Override
	public void processors(Class<?> clazz, EntityMetaData metadata) throws ElementProcessorException {
		validators(clazz, metadata);
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {

			// validated, at all places below
			OneToOne oneToOneAnn = field.getAnnotation(OneToOne.class);
			if (oneToOneAnn == null)
				continue;
			if (Loggerfactory.isdebug(logger))
				Loggerfactory.info(logger, "processors   OneToOne Relation to   Metadata   " + field.getName() + "  EntityMetadata " + metadata);
			// taking field's type as foreign entity, ignoring "targetEntity"
			Class<?> targetEntity = field.getType();
			if (Loggerfactory.isdebug(logger))
				Loggerfactory.info(logger, "add  OneToOne Relation  :    " + field.getName() + "  EntityMetadata " + metadata);
			boolean isJoinedByPK = field.isAnnotationPresent(PrimaryKeyJoinColumn.class);
			boolean isJoinedByFK = field.isAnnotationPresent(JoinColumn.class);
			boolean isJoinedByTable = field.isAnnotationPresent(JoinTable.class);

			/*
			 * if(!isJoinedByPK && !isJoinedByFK) { throw new
			 * PersistenceException(
			 * "A one-to-one relationship must have either JoinColumn or PrimaryKeyJoinColumn annotation"
			 * ); }
			 */

			Relation relation = new Relation(field, targetEntity, null, oneToOneAnn.fetch(), Arrays.asList(oneToOneAnn.cascade()), oneToOneAnn.optional(), oneToOneAnn.mappedBy(),
					Relation.ForeignKey.ONE_TO_ONE);

			if (isJoinedByPK) {
				relation.setJoinedByPrimaryKey(true);
			} else if (isJoinedByFK) {
				JoinColumn joinColumnAnn = field.getAnnotation(JoinColumn.class);
				relation.setJoinColumnName(joinColumnAnn.name());
			} else if (isJoinedByTable) {
				//				JoinTableMetadata jtMetadata = new JoinTableMetadata(relationField);
				//				relation.setRelatedViaJoinTable(true);
				//				relation.setJoinTableMetadata(jtMetadata);
				throw new JPASQLRunTimeException("this is not work ! ");
			}
			Loggerfactory.info(logger, "EntityMetadata  " + metadata.getEntityClazz().getSimpleName() + "add Relation  : " + relation);
			EntityFields entityFields = (EntityFields) ((EntityMetaData) metadata).getEntityField(field.getName());

			if (entityFields.getjPAField() == null) {
				JPAField jpaFieldImpl = new JPAField(true);
				jpaFieldImpl.setRelation(relation);
				entityFields.setjPAField(jpaFieldImpl);
			} else {
				if (entityFields.getjPAField().getRelation() != null)
					throw new ElementProcessorException("this entity : " + clazz.getSimpleName() + "  field : [ " + field.getName() + " ]   have  relation : "
							+ entityFields.getjPAField().getRelation().getType() + " ;  but this  set  " + relation.getType());
			}

		}

	}

}
